#![allow(missing_docs)]

use unsafe_list::{UnsafeListHead, UnsafeListNode, define_unsafe_list_head, init_unsafe_list_head};

struct Head {
    str: String,
    head: UnsafeListHead<Node>,
}

struct Node {
    val: usize,
    list: UnsafeListNode<Node>,
}

impl Node {
    pub fn create(val: usize) -> Self {
        Self { val, list: UnsafeListNode::new() }
    }
}

static mut TEST_HEAD: Head = Head { str: String::new(), head: UnsafeListHead::new() };

#[test]
#[allow(unsafe_code, static_mut_refs)]
fn list_test() {
    unsafe {
        TEST_HEAD.str = String::from("head");
        let head = &mut TEST_HEAD.head;
        init_unsafe_list_head!(head, Node, list);

        assert!(TEST_HEAD.head.list_empty());
        let mut one = Node::create(1);
        let mut two = Node::create(2);
        let mut three = Node::create(3);
        let mut four = Node::create(4);
        let mut five = Node::create(5);
        let mut six = Node::create(6);
        TEST_HEAD.head.list_add(&mut one.list);
        TEST_HEAD.head.list_add(&mut two.list);
        TEST_HEAD.head.list_add(&mut three.list);
        TEST_HEAD.head.list_add(&mut four.list);
        TEST_HEAD.head.list_add(&mut five.list);
        TEST_HEAD.head.list_add(&mut six.list);

        assert!(!TEST_HEAD.head.list_empty());

        let first = TEST_HEAD.head.list_first_entry();
        assert_eq!(first.val, 6);

        let last = TEST_HEAD.head.list_last_entry();
        assert_eq!(last.val, 1);

        let mut last = Node::create(0);
        TEST_HEAD.head.list_add_tail(&mut last.list);
        let last = TEST_HEAD.head.list_last_entry();
        assert_eq!(last.val, 0);

        let check = [6, 5, 4, 3, 2, 1, 0];
        let mut i = 0;
        for this in TEST_HEAD.head.iter() {
            assert_eq!(this.val, check[i]);
            i += 1;
        }

        let check_rev = [0, 1, 2, 3, 4, 5, 6];
        i = 0;
        for this in TEST_HEAD.head.iter().rev() {
            assert_eq!(this.val, check_rev[i]);
            i += 1;
        }

        define_unsafe_list_head!(head, Node, list);
        assert!(head.list_empty());

        let mut one = Node::create(1);
        let mut two = Node::create(2);
        let mut three = Node::create(3);
        let mut four = Node::create(4);
        let mut five = Node::create(5);
        let mut six = Node::create(6);
        head.list_add(&mut one.list);
        head.list_add(&mut two.list);
        head.list_add(&mut three.list);
        head.list_add(&mut four.list);
        head.list_add(&mut five.list);
        head.list_add(&mut six.list);
        assert!(!head.list_empty());

        let check = [6, 5, 4, 3, 2, 1];
        let mut i = 0;
        for this in head.iter_mut() {
            assert_eq!(this.val, check[i]);
            i += 1;
        }

        define_unsafe_list_head!(head, Node, list);
        assert!(head.list_empty());

        let mut one = Node::create(1);
        let mut two = Node::create(2);
        let mut three = Node::create(3);
        let mut four = Node::create(4);
        let mut five = Node::create(5);
        let mut six = Node::create(6);
        head.list_add_tail(&mut one.list);
        head.list_add_tail(&mut two.list);
        head.list_add_tail(&mut three.list);
        head.list_add_tail(&mut four.list);
        head.list_add_tail(&mut five.list);
        head.list_add_tail(&mut six.list);
        assert!(!head.list_empty());

        let check = [1, 2, 3, 4, 5, 6];
        let mut i = 0;
        for this in head.iter_mut() {
            assert_eq!(this.val, check[i]);
            i += 1;
        }

        define_unsafe_list_head!(head, Node, list);
        assert!(head.list_empty());
        for _ in head.iter() {
            assert!(false);
        }
        for _ in head.iter().rev() {
            assert!(false);
        }
        for _ in head.iter_mut().rev() {
            assert!(false);
        }
    }
}
